//
//  BBConfigurationController.m
//  BBTouch
//
//  This file is part of BBTouch.
//
//  BBTouch is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.

//  BBTouch is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.

//  You should have received a copy of the GNU Lesser General Public License
//  along with BBTouch.  If not, see <http://www.gnu.org/licenses/>.
// 
//  Copyright 2008 Ben Britten Smith ben@benbritten.com .
// 
//  Created by ben smith on 5/30/08.
//

#import "BBConfigurationController.h"
#import "BBApplicationSupport.h"
#import "BBDistortionMap.h"
#import "BBMeshController.h"


@implementation BBConfigurationController
BBConfigurationController* sharedConfigurationController;

@synthesize configurationSettings;

-(void)awakeFromNib
{
	self.configurationSettings = [NSMutableDictionary dictionary];
	configurationLibrary = [[NSMutableArray alloc] init];
	sharedConfigurationController = self;
	[self loadDefaultConfiguration];
	[self loadConfigLibrary];
	
	[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"BBRawVideoSizeStringValue" options:NSKeyValueObservingOptionNew context:nil];
	// NOTE: it is very important that we set the raw image size first, the ROI checks itself against the raw image size
	// so if ti is not set, then the ROI gets all messed up
	[self setRawImageSize:NSSizeFromString([BBConfigurationController objectForSettingKey:@"BBRawVideoSizeStringValue"])]; 
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appQuit:) name:@"NSApplicationWillTerminateNotification" object:nil];

}

// this is a bit of a hack, I should do the user-friendly thing and shut down the camera object and re-initialize with the new
// size, but for now we will go with the manual user-driven method.
// TODO: fix the hackiness of this
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
	// this is just here to notify the suer when they try to change the video size
	if ([keyPath isEqualToString:@"BBRawVideoSizeStringValue"]) {
		[[NSAlert alertWithMessageText:@"Image Re-size requires a restart" defaultButton:@"Oh, ok." alternateButton:nil otherButton:nil informativeTextWithFormat:@"Please quit BBTouch and re-open it for the video size changes to take effect."] runModal];
	}
}

-(void)appQuit:(id)sender
{
	[self saveDefaultConfiguration];
	[self saveConfigLibrary];
}

// this allows any concerned object to access the NIB generated instance of this object
+(BBConfigurationController*)sharedConfigurationController
{
	return sharedConfigurationController;
}

// returns the current configuration setting for the specified key
+(BOOL)boolForSettingKey:(NSString*)key
{
	return [[sharedConfigurationController.configurationSettings objectForKey:key] boolValue];
}

+(NSInteger)intForSettingKey:(NSString*)key
{
	return [[sharedConfigurationController.configurationSettings objectForKey:key] integerValue];
}

+(NSMutableDictionary*)configurationSettings
{
	return sharedConfigurationController.configurationSettings;
}

+(id)objectForSettingKey:(NSString*)key
{
	return [sharedConfigurationController.configurationSettings objectForKey:key];
}

+(void)setObject:(id)object forSettingKey:(NSString*)key
{
	[sharedConfigurationController.configurationSettings setObject:object forKey:key];
}

// just a nice method to set some sane inital defaults for the first time you use the app
-(void)setInitialDefaults
{
	[self setDefault:[NSNumber numberWithBool:NO] forKey:@"BBGenerateTUIOFlag"];
	[self setDefault:[NSNumber numberWithInt:3333] forKey:@"BBGenerateTUIOPort"];
	[self setDefault:@"127.0.0.1" forKey:@"BBGenerateTUIOHost"];
	[self setDefault:@"Unnamed settings" forKey:@"BBConfigName"];

	[self setDefault:[NSNumber numberWithFloat:2.1] forKey:@"BBBlobMinimunRadius"];

	[self setDefault:[NSNumber numberWithBool:YES] forKey:@"BBShowRawVideoFlag"];
	[self setDefault:[NSNumber numberWithBool:NO] forKey:@"BBInvertBlobCheck"];
	[self setDefault:[NSNumber numberWithInt:100] forKey:@"BBMainThreshold"];
	[self setDefault:[NSNumber numberWithInt:20] forKey:@"BBBlobMatchingDistance"];
	[self setDefault:[NSNumber numberWithInt:6] forKey:@"BBBlobJitterDistance"];
	
	[self setDefault:[NSNumber numberWithInt:19] forKey:@"BBHighPassKernelSize"];
	[self setDefault:[NSNumber numberWithInt:7] forKey:@"BBNoiseKernelSize"];
	[self setDefault:[NSNumber numberWithInt:15] forKey:@"BBThresholdKernelSize"];
	[self setDefault:[NSNumber numberWithInt:-2] forKey:@"BBThresholdMedianOffset"];
	
	[self setDefault:NSStringFromSize(NSMakeSize(640, 480)) forKey:@"BBRawVideoSizeStringValue"];
}

-(IBAction)openTUIOSheet:(id)sender;
{
	[NSApp beginSheet:tuioSheet modalForWindow:mainWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}

-(IBAction)endTUIOSheet:(id)sender;
{
	[NSApp endSheet:tuioSheet];
	[tuioSheet orderOut:sender];
}

-(IBAction)openScreenSheet:(id)sender;
{
	[NSApp beginSheet:screenSheet modalForWindow:mainWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}

-(IBAction)endScreenSheet:(id)sender;
{
	[NSApp endSheet:screenSheet];
	[screenSheet orderOut:sender];
}


-(IBAction)openArchiveSheet:(id)sender;
{
	[NSApp beginSheet:archiveSheet modalForWindow:mainWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}

-(IBAction)endArchiveSheet:(id)sender;
{
	[NSApp endSheet:archiveSheet];
	[archiveSheet orderOut:sender];
}


-(void)saveDefaultConfiguration
{
	
	NSString * supportDir = [BBApplicationSupport applicationSupportFolder];
	NSString * configFile = [supportDir stringByAppendingPathComponent:@"BBConfigurationData.plist"];
	BOOL result = [self.configurationSettings writeToFile:configFile atomically:YES];
	
	// TODO: make this nicer
	if (!result)
		[[NSAlert alertWithMessageText:@"Cannot archive Default Config File!" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"There was an error saving to the file: %@",configFile] runModal];
}

-(void)saveConfigLibrary
{
	NSString * supportDir = [BBApplicationSupport applicationSupportFolder];
	NSString * libFile = [supportDir stringByAppendingPathComponent:@"BBConfigurationLibrary.plist"];
	BOOL result = [configurationLibrary writeToFile:libFile atomically:YES];
	
	// TODO: make this nicer
	if (!result)
		[[NSAlert alertWithMessageText:@"Cannot archive Config Library!" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"There was an error saving to the file: %@",libFile] runModal];	
}

-(void)loadDefaultConfiguration
{
	NSString * configFile = [BBApplicationSupport pathForApplicationSupportFileWithName:@"BBConfigurationData.plist"];
	if (configFile == nil) {
		[self setInitialDefaults];
		return;
	}
	self.configurationSettings = [NSDictionary dictionaryWithContentsOfFile:configFile];
}
	
-(IBAction)addNewConfig:(id)sender
{
	[configurationSettings setObject:@"New Config" forKey:@"BBConfigName"];
	NSMutableDictionary * newConfig = [[NSMutableDictionary alloc] initWithDictionary:configurationSettings copyItems:YES];
	BBDistortionMap * mapToArchive = [[BBMeshController sharedMeshController] distortionMap];
	NSData * meshData = [NSKeyedArchiver archivedDataWithRootObject:mapToArchive];
	[newConfig setObject:meshData forKey:@"BBArchivedMeshData"];
	[libraryController addObject:newConfig];
	[newConfig release];
}

-(IBAction)loadConfig:(id)sender
{
	NSDictionary * archivedDict = [[libraryController arrangedObjects] objectAtIndex:[libraryController selectionIndex]];
	NSMutableDictionary * newConfig = [[NSMutableDictionary alloc] initWithDictionary:archivedDict copyItems:YES];
	[configurationSettings removeAllObjects];
	[configurationSettings addEntriesFromDictionary:newConfig];

	NSData * meshData = [configurationSettings objectForKey:@"BBArchivedMeshData"];
	BBDistortionMap * mapFromArchive = [NSKeyedUnarchiver unarchiveObjectWithData:meshData];	
	[[BBMeshController sharedMeshController] loadFromUnarchivedMap:mapFromArchive];
	
	[newConfig release];
}

	
-(void)loadConfigLibrary
{
	NSString * configLibraryFile = [BBApplicationSupport pathForApplicationSupportFileWithName:@"BBConfigurationLibrary.plist"];
	if (configLibraryFile == nil) return;
	NSArray * archive = [NSArray arrayWithContentsOfFile:configLibraryFile];
	[libraryController addObjects:archive];
}

-(void)setDefault:(id)obj forKey:(id)key
{
	if ([configurationSettings objectForKey:key] == nil) {
		[configurationSettings setObject:obj forKey:key];		
	}
}

-(NSArray*)allowableRawImageSizes
{
	// returns an array with the image sizes that are available to the user
	return [NSArray arrayWithObjects:NSStringFromSize(NSMakeSize(640, 480)),NSStringFromSize(NSMakeSize(400, 300)),NSStringFromSize(NSMakeSize(320, 240)),NSStringFromSize(NSMakeSize(160, 120)),nil];
}


-(void)setRawImageSize:(NSSize)aSize
{
	// need to check the new settings against the raw size. we never want to ROI to be as big as the raw size,
	// in order for the blob detection to work properly, it needs to be at least one pixel in
	rawImageSize = aSize;
}


-(NSSize)rawImageSize
{
	// TODO: make this into a drop down option or something
	return rawImageSize;
}

- (void) dealloc
{
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[super dealloc];
}



@end
